use crate::common::AppState;
use crate::handler::api::handler::__path_sign;
use crate::vo::user::UserLoginReqVo;
use axum::Router;
use std::sync::Arc;
use utoipa::{
    openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme},
    Modify, OpenApi,
};
use utoipa_rapidoc::RapiDoc;
use utoipa_redoc::{Redoc, Servable};
use utoipa_swagger_ui::SwaggerUi;

pub(crate) trait OpenApiRouter {
    fn openapi(self) -> Self;
}

#[derive(OpenApi)]
#[openapi(
    paths(
        sign
    ),
    components(
        schemas(UserLoginReqVo),
    ),
    modifiers(&SecurityAddon),
    tags(
            (name = "chat", description = "Chat related operations"),
    )
)]
pub(crate) struct ApiDoc;

struct SecurityAddon;

impl Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            components.add_security_scheme(
                "token",
                SecurityScheme::Http(HttpBuilder::new().scheme(HttpAuthScheme::Bearer).build()),
            )
        }
    }
}

impl OpenApiRouter for Router<Arc<AppState>> {
    fn openapi(self) -> Self {
        let scheme: Router<Arc<AppState>> = SwaggerUi::new("/swagger-ui")
            .url("/api-docs/openapi.json", ApiDoc::openapi())
            .into();
        let redoc: Router<Arc<AppState>> = Redoc::with_url("/redoc", ApiDoc::openapi()).into();
        let rapidoc: Router<Arc<AppState>> = RapiDoc::new("/api-docs/openapi.json")
            .path("/rapidoc")
            .into();
        self.merge(scheme).merge(redoc).merge(rapidoc)
    }
}
